/*
 * @Description:快捷调用
 * @Author: maskMan
 * @LastEditTime: 2024-04-04 15:33:02
 */

import {
  Animation,
  AudioClip,
  Camera,
  Component,
  EventTouch,
  find,
  geometry,
  instantiate,
  isValid,
  macro,
  Material,
  MeshRenderer,
  Node,
  Prefab,
  Size,
  SkeletalAnimation,
  sp,
  Sprite,
  SpriteFrame,
  tween,
  UITransform,
  v2,
  v3,
  Vec2,
  Vec3,
  __private
} from 'cc'
import { ActionRet, DIR_KEY } from '../define/constants'
import AudioManager from './audioManager'
import ResManager from './resManager'
export default class QuickManager extends Component {
  static instance: QuickManager
  /**游戏更新帧率 */
  deltaTime: number
  /**获取当前Canvas*/
  getCanvasNode(): Node {
    const ret = find('Canvas')
    return ret
  }
  /**
   * @description: 加载插入预制体
   * @param {Partial} scData 数据
   * @param {string} preName 预制体名字
   * @param {DIR_KEY} dir  路径
   * @return {*}
   */
  loadInsertPrefab<T>(preName: string, scData: Partial<T> = {}, dir?: DIR_KEY.PREPUB | DIR_KEY.PREGAME, parent?: Node): Promise<Node> {
    return new Promise(async (resolve) => {
      try {
        const parentNode = parent == undefined ? this.getCanvasNode() : parent
        const pre = await ResManager.loadPrefab(preName, dir)
        if (pre && Array.isArray(pre) == false) {
          const p = instantiate(pre) as unknown as Node
          const sc = p.getComponent(`${p.name}`) as T
          if (sc) {
            for (const k in scData) {
              if (sc[k] != undefined) {
                sc[k] = scData[k]
              }
            }
          }
          parentNode.addChild(p)
          return resolve(p)
        }
        return resolve(null)
      } catch (error) {
        console.log(error)
        return resolve(null)
      }
    })
  }
  /**
   * @description: 创建预制体
   * @param {Prefab} pre 预制体
   * @param {Partial} scData 数据
   * @param {Node} parent 父节点
   * @return {*}
   */
  createPrefab<T>(pre: Prefab | Node, scData: Partial<T> = {}, parent?: Node): Promise<Node> {
    return new Promise(async (resolve) => {
      try {
        const parentNode = parent == undefined ? this.getCanvasNode() : parent
        const p = instantiate(pre) as unknown as Node
        const sc = p.getComponent(`${p.name}`) as T
        if (sc) {
          for (const k in scData) {
            if (sc[k] != undefined) {
              sc[k] = scData[k]
            }
          }
        }
        parentNode.addChild(p)
        return resolve(p)
      } catch (error) {
        console.log(error)
        return resolve(null)
      }
    })
  }
  /**
   * @description: 加载并播放音效
   * @param {string} soundName
   * @param {boolean} loop
   * @return {*}
   */
  loadPlaySound(soundName: string, loop: boolean = false): Promise<AudioClip> {
    return new Promise(async (resolve) => {
      try {
        const soundClip = (await ResManager.loadAudio(soundName, DIR_KEY.SOUND)) as AudioClip
        if (soundClip && Array.isArray(soundClip) == false) {
          AudioManager.playSound(soundClip, loop)
          return resolve(soundClip)
        }
        console.error('未找到音效')
        return resolve(null)
      } catch (error) {
        console.error(error)
        return resolve(null)
      }
    })
  }
  /**
   * @description: 加载并播放音乐
   * @param {string} musicName
   * @param {boolean} loop
   * @return {*}
   */
  loadPlayMusic(musicName: string, loop: boolean = true): Promise<AudioClip> {
    return new Promise(async (resolve) => {
      try {
        const musicClip = (await ResManager.loadAudio(musicName, DIR_KEY.MUSIC)) as AudioClip
        if (musicClip && Array.isArray(musicClip) == false) {
          AudioManager.playSound(musicClip, loop)
          return resolve(musicClip)
        }
        console.error('未找到音效')
        return resolve(null)
      } catch (error) {
        console.error(error)
        return resolve(null)
      }
    })
  }
  /**
   * @description: 加载设置精灵帧
   * @param {string} spName 精灵帧名字
   * @param {Node} masterNode 节点名字
   * @param {DIR_KEY} dir 加载路径
   * @return {*}
   */
  loadSetSpriteFrame(spName: string, masterNode: Node, dir?: DIR_KEY.LOADSP | DIR_KEY.BASETEXTURE): Promise<SpriteFrame> {
    return new Promise(async (resolve) => {
      try {
        const spriteFrame = (await ResManager.loadSpriteFrame(spName, dir)) as SpriteFrame
        if (spriteFrame && Array.isArray(spriteFrame) == false) {
          masterNode.getComponent(Sprite).spriteFrame = spriteFrame
          return resolve(spriteFrame)
        }
        console.error('未找到精灵帧')
        return resolve(null)
      } catch (error) {
        console.error(error)
        return resolve(null)
      }
    })
  }
  /**
   * @description: 加载设置节点材质
   * @param {string} mateName 材质名字
   * @param {Node} masterNode 节点名
   * @param {number} posIndex 设置顺序
   * @param {DIR_KEY} dir  加载路径
   * @return {*}
   */
  loadSetMaterial(mateName: string, masterNode: Node, posIndex: number = 0, dir?: DIR_KEY.MATERIAGAME | DIR_KEY.MATERIAPUB): Promise<Material> {
    return new Promise(async (resolve) => {
      try {
        const material = (await ResManager.loadMaterial(mateName, dir)) as Material
        if (material && Array.isArray(material) == false) {
          const mate = masterNode.getComponent(MeshRenderer).materials
          if (mate.length >= posIndex + 1) {
            mate[posIndex] = material
          } else {
            mate.push(material)
          }
          return resolve(material)
        }
        console.error('未找到精灵帧')
        return resolve(null)
      } catch (error) {
        console.error(error)
        return resolve(null)
      }
    })
  }
  /**
   * @description: 设置节点材质
   * @param {Material} mater 材质
   * @param {Node} masterNode  节点名字
   * @param {number} posIndex 设置顺序
   * @return {*}
   */
  setMaterial(material: Material, masterNode: Node, posIndex: number = 0): Promise<Material> {
    return new Promise(async (resolve) => {
      try {
        const mate = masterNode.getComponent(MeshRenderer).materials
        if (mate.length >= posIndex + 1) {
          mate[posIndex] = material
        } else {
          mate.push(material)
        }
        return resolve(material)
      } catch (error) {
        console.error(error)
        return resolve(null)
      }
    })
  }
  /**
   * @description: 帧移动到指定坐标
   * @param {Node} targetNode  节点
   * @param {Vec3} targetPos 目的坐标
   * @param {Vec3} offsetSpeed 移动速度
   * @return {*}
   */
  updateMoveTo(targetNode: Node, targetPos: Vec3, offsetSpeed: Vec3): Promise<Node> {
    try {
      return new Promise((resolve) => {
        const dis = Vec3.squaredDistance(targetPos, targetNode.getPosition())
        if (dis < 6) {
          return resolve(targetNode)
        }
        const self = this
        let minValue = macro.REPEAT_FOREVER
        const tarPos = targetPos.clone().normalize()
        let timerCall = function () {
          if (isValid(targetNode) == false) {
            self.unschedule(timerCall)
            return resolve(targetNode)
          }
          const x = tarPos.x * self.deltaTime * offsetSpeed.x
          const y = tarPos.y * self.deltaTime * offsetSpeed.y
          const z = tarPos.z * self.deltaTime * offsetSpeed.z
          const pos = self.getNodeOffset(targetNode, v3(x, y, z))
          const dis = Vec3.squaredDistance(targetPos, pos)
          if (dis < minValue) {
            targetNode.setPosition(pos)
            minValue = dis
          } else {
            self.unschedule(timerCall)
            return resolve(targetNode)
          }
        }
        this.schedule(timerCall)
      })
    } catch (error) {
      console.error(error)
    }
  }
  /**
   * @description: 获取迭代节点坐标
   * @param {Node} targetNode 目标节点
   * @param {Vec3} offset 迭代量
   * @return {*}
   */
  getNodeOffset(targetNode: Node, offset: Vec3): Vec3 {
    const pos = targetNode.getPosition()
    pos.add(offset)
    return pos
  }
  /**
   * @description: 获取容器坐标列表
   * @param {Node} content 容器父节点
   * @param {Node} targetNode 子节点
   * @param {number} createCount 创建数量
   * @param {Vec2} interVal 间隔
   * @param {number} rowCount 行的数量
   * @return {*}
   */
  getContentPosList(content: Node | Size, targetNode: Node | Size, createCount: number, interVal: Vec2 = v2(10, 10), rowCount?: number): Vec3[] {
    try {
      const contentSize = content instanceof Node ? content.getComponent(UITransform).contentSize : content
      const targetSize = targetNode instanceof Node ? targetNode.getComponent(UITransform).contentSize : targetNode
      const targetWidth = targetSize.width + interVal.x
      const targetHeight = targetSize.height + interVal.y
      const max_count = Math.floor(contentSize.width / targetWidth)
      const row_count = rowCount ? (rowCount > max_count ? max_count : rowCount) : max_count
      let x = 0
      let y = 0
      let z = 0
      const list: Vec3[] = []
      for (let i = 0; i < createCount; i++) {
        y = i * targetHeight + targetHeight / 2 - contentSize.height / 2
        for (let t = 0; t < row_count; t++) {
          x = t * targetWidth + targetWidth / 2 - contentSize.width / 2
        }
        list.push(v3(x, y, z))
      }
      return list
    } catch (error) {
      console.error(error)
    }
  }
  /**
   * @description: 获取半径圆内的坐标点
   * @param {number} radius 半径
   * @param {number} count  坐标点数量
   * @return {*}
   */
  getCirclePosList(radius: number, count: number): Vec3[] {
    const list: Vec3[] = []
    const r = radius
    for (let i = 0; i < count; i++) {
      const radian = (Math.PI / 180) * i * 10
      const x = Math.sin(radian) * r
      const y = Math.cos(radian) * r
      const z = 0
      list.push(v3(x, y, z))
    }
    return list
  }
  /**播放spine动画 */
  playSpineAnimation(spineNode: Node, aniName: string, loop: boolean = true, skinName?: string) {
    try {
      return new Promise((resolve) => {
        if (skinName) {
          spineNode.getComponent(sp.Skeleton).setSkin(skinName)
        }
        if (spineNode.active == false) {
          spineNode.active = true
        }
        const spData = spineNode.getComponent(sp.Skeleton)
        const ret = spData.findAnimation(aniName)
        if (ret) {
          spData.setAnimation(0, aniName, loop)
          if (loop == false) {
            spData.setCompleteListener(() => {
              return resolve(spData)
            })
          } else {
            return resolve(spData)
          }
        } else {
          console.log('动画不存在')
          return resolve(null)
        }
      })
    } catch (error) {
      console.log(error)
    }
  }
  /**
   * @description:   播放蒙皮动画
   * @param {Node} aniNode 动画节点
   * @param {string} aniName 动画名字
   * @param {boolean} isPlay 是否播放/仅仅监听
   * @return {*}
   */
  playSkelAnimation(aniNode: Node, aniName?: string): Promise<SkeletalAnimation> {
    try {
      return new Promise((resolve) => {
        if (aniNode.active == false) {
          aniNode.active = true
        }
        const aniData = aniNode.getComponent(SkeletalAnimation)
        aniData.play(aniName)
        if (aniData) {
          const finished = 'finished' as __private._cocos_animation_animation_state__EventType.FINISHED
          aniData.once(finished, () => {
            return resolve(aniData)
          })
        } else {
          console.log('动画不存在')
          return resolve(null)
        }
      })
    } catch (error) {
      console.log(error)
    }
  }
  /**
   * @description:   播放animation动画
   * @param {Node} aniNode 动画节点
   * @param {string} aniName 动画名字
   * @param {boolean} isPlay 是否播放/仅仅监听
   * @return {*}
   */
  playAnimation(aniNode: Node, aniName?: string): Promise<Animation> {
    try {
      return new Promise((resolve) => {
        if (aniNode.active == false) {
          aniNode.active = true
        }
        const aniData = aniNode.getComponent(Animation)
        aniData.play(aniName)
        if (aniData) {
          const finished = 'finished' as __private._cocos_animation_animation_state__EventType.FINISHED
          aniData.once(finished, () => {
            return resolve(aniData)
          })
        } else {
          console.log('动画不存在')
          return resolve(null)
        }
      })
    } catch (error) {
      console.log(error)
    }
  }
  /**
   * @description: 转换当前坐标到目标节点下
   * @param {Node} targetNode 目标节点
   * @param {Node} currNode 当前坐标
   * @return {*}
   */
  convertToTargetPosUI(targetNode: Node, currNode: Node): Vec3 {
    try {
      const tar = targetNode.parent.getComponent(UITransform)
      const curr = currNode.getComponent(UITransform)
      const currWord = curr.convertToWorldSpaceAR(Vec3.ZERO)
      const ret = tar.convertToNodeSpaceAR(currWord)
      return ret
    } catch (error) {
      console.error(error)
    }
  }
  /**
   * @description: 转换当前坐标到世界坐标点下
   * @param {Node} currNode 当前坐标
   * @return {*}
   */
  convertToWordUI(currNode: Node): Vec3 {
    try {
      const curr = currNode.getComponent(UITransform)
      const currWord = curr.convertToWorldSpaceAR(Vec3.ZERO)
      return currWord
    } catch (error) {
      console.error(error)
    }
  }
  /**
   * @description: 是否触摸到模型
   * @param {EventTouch} touch UI触摸事件
   * @param {Node} tarNode 模型节点
   * @param {Camera} camera 摄像机
   * @return {*}
   */
  isTouchGameModel(touch: EventTouch, tarNode: Node, camera: Camera): boolean {
    const loacl = touch.getUILocation()
    const ray = camera.screenPointToRay(loacl.x, loacl.y)
    const bouns = tarNode.getComponent(MeshRenderer).model.worldBounds
    return geometry.intersect.rayAABB(ray, bouns) != 0 ? true : false
  }
}
